<!DOCTYPE HTML>
<html>

<head>
	<link rel="bookmark"  type="image/x-icon"  href="/img/logo_miccall.png"/>
	<link rel="shortcut icon" href="/img/logo_miccall.png">
	
			    <title>
    Ame雨
    </title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
    <link rel="stylesheet" href="/amelin-ting/css/mic_main.css" />
    <link rel="stylesheet" href="/amelin-ting/css/dropdownMenu.css" />
    <meta name="keywords" content="Ame雨" />
    
    	<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
	 
    <noscript>
        <link rel="stylesheet" href="/amelin-ting/css/noscript.css" />
    </noscript>
    <style type="text/css">
        body:before {
          content: ' ';
          position: fixed;
          top: 0;
          background: url('/amelin-ting/img/bg.jpg') center 0 no-repeat;
          right: 0;
          bottom: 0;
          left: 0;
          background-size: cover; 
        }
    </style>

			    
  
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script async type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
  


    <script src="/amelin-ting/js/jquery.min.js"></script>
    <script src="/amelin-ting/js/jquery.scrollex.min.js"></script>
    <script src="/amelin-ting/js/jquery.scrolly.min.js"></script>
    <script src="/amelin-ting/js/skel.min.js"></script>
    <script src="/amelin-ting/js/util.js"></script>
    <script src="/amelin-ting/js/main.js"></script>
	
<meta name="generator" content="Hexo 5.4.0"></head>
    
		
<!-- Layouts -->



<!--  代码渲染  -->
<link rel="stylesheet" href="/css/prism_coy.css" />
<link rel="stylesheet" href="/css/typo.css" />
<!-- 文章页 -->
<body class="is-loading">
    <!-- Wrapper 外包 s-->
    <div id="wrapper" class="fade-in">
        <!-- Intro 头部显示 s -->
        <!-- Intro 头部显示 e -->
        <!-- Header 头部logo start -->
        <header id="header">
    <a href="/amelin-ting/" class="logo">Art Space</a>
</header>
        <!-- Nav 导航条 start -->
        <nav id="nav" class="special" >
            <ul class="menu links" >
			<!-- Homepage  主页  --> 
			<li >
	            <a href="/amelin-ting/" rel="nofollow">主页</a>
	        </li>
			<!-- categories_name  分类   --> 
	        
	        <li class="active">
	            <a href="#s1">分类</a>
	                    <ul class="submenu">
	                        <li>
	                        <a class="category-link" href="/amelin-ting/categories/Go/">Go</a></li><li><a class="category-link" href="/amelin-ting/categories/django/">django</a></li><li><a class="category-link" href="/amelin-ting/categories/drf/">drf</a></li><li><a class="category-link" href="/amelin-ting/categories/gin/">gin</a></li><li><a class="category-link" href="/amelin-ting/categories/go/">go</a></li><li><a class="category-link" href="/amelin-ting/categories/linux/">linux</a></li><li><a class="category-link" href="/amelin-ting/categories/mysql/">mysql</a></li><li><a class="category-link" href="/amelin-ting/categories/python/">python</a></li><li><a class="category-link" href="/amelin-ting/categories/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/">内网穿透</a></li><li><a class="category-link" href="/amelin-ting/categories/%E5%89%8D%E7%AB%AF/">前端</a>
	                    </ul>
	        </li>
	        
	        <!-- archives  归档   --> 
	        
	        
		        <!-- Pages 自定义   -->
		        
		        <li>
		            <a href="/about/" title="简历">
		                简历
		            </a>
		        </li>
		        
		        <li>
		            <a href="/group/" title="团队">
		                团队
		            </a>
		        </li>
		        
		        <li>
		            <a href="/gallery/" title="图库">
		                图库
		            </a>
		        </li>
		        
		        <li>
		            <a href="/tag/" title="标签">
		                标签
		            </a>
		        </li>
		        


            </ul>
            <!-- icons 图标   -->
			<ul class="icons">
                    
                    <li>
                        <a title="github" href="https://github.com/miccall" target="_blank" rel="noopener">
                            <i class="icon fa fa-github"></i>
                        </a>
                    </li>
                    
                    <li>
                        <a title="500px" href="http://500px.com" target="_blank" rel="noopener">
                            <i class="icon fa fa-500px"></i>
                        </a>
                    </li>
                    
			</ul>
</nav>

        <div id="main" >
            <div class ="post_page_title_img" style="height: 25rem;background-image: url(https://img0.baidu.com/it/u=163753268,4219163955&amp;fm=26&amp;fmt=auto);background-position: center; background-repeat:no-repeat; background-size:cover;-moz-background-size:cover;overflow:hidden;" >
                <a href="#" style="padding: 4rem 4rem 2rem 4rem ;"><h2 >python网络编程</h2></a>
            </div>
            <!-- Post -->
            <div class="typo" style="padding: 3rem;">
                <h1 id="网络编程"><a href="#网络编程" class="headerlink" title="网络编程"></a>网络编程</h1><h2 id="一、-套接字介绍"><a href="#一、-套接字介绍" class="headerlink" title="一、 套接字介绍"></a>一、 套接字介绍</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	套接字是从20世纪70年代的加利福尼亚大学的伯克利分校版本的UNIX起源的，即人们所说的 BSD Unix，因此，有时人们也把套接字称为 ‘伯克利套接字’或者‘BSD 套接字’，但是那时候的套接字是用在同一台计算机的不同程序之间的通信，也被称为进程型通信</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># 套接字有两种</span></span><br><span class="line">	<span class="number">1.</span>基于文件的套接字</span><br><span class="line">    	套接字家族的名字：AF_UNIX</span><br><span class="line">    <span class="number">2.</span>基于网络的套接字</span><br><span class="line">    	套接字家族的名字：AF_INET</span><br><span class="line"><span class="comment"># 套接字的工作流程</span></span><br><span class="line">	套接字是将传输层以下全部打包，但是跟我们有关系的只有TCP UDP  只需要基于这两个来写套接字的软件就好了</span><br></pre></td></tr></table></figure>

<h2 id="二、位于TCP协议的套接字通信流程介绍"><a href="#二、位于TCP协议的套接字通信流程介绍" class="headerlink" title="二、位于TCP协议的套接字通信流程介绍"></a>二、位于TCP协议的套接字通信流程介绍</h2><h2 id="三、基于TCP协议的简单套接字通信"><a href="#三、基于TCP协议的简单套接字通信" class="headerlink" title="三、基于TCP协议的简单套接字通信"></a>三、基于TCP协议的简单套接字通信</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 可以用手机来形容整个过程</span></span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    iphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  <span class="comment"># 流式协议</span></span><br><span class="line">    <span class="comment"># 装手机卡</span></span><br><span class="line">    iphone.bind((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line">    <span class="comment"># 开机</span></span><br><span class="line">    iphone.listen(<span class="number">5</span>)  <span class="comment"># 5指的是半连接池的大小</span></span><br><span class="line">    <span class="comment"># 等人打电话：拿到电话连接conn</span></span><br><span class="line">   </span><br><span class="line">    conn, client_addr = iphone.accept()</span><br><span class="line">    <span class="built_in">print</span>(conn)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;客户端的IP和端口&#x27;</span>, client_addr)</span><br><span class="line">    <span class="comment"># 通信中 </span></span><br><span class="line">    data = conn.recv(<span class="number">1024</span>)  <span class="comment"># 最大接受量为1024个字节</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;客户端收来的消息数据&#x27;</span>, data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">    conn.send(data.upper())</span><br><span class="line">    <span class="comment"># 关闭通信</span></span><br><span class="line">    conn.close()</span><br><span class="line">    <span class="comment"># 关闭手机（可选操作）</span></span><br><span class="line">    iphone.close()</span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 直接拨打电话</span></span><br><span class="line">    phone.connect((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 通信</span></span><br><span class="line">    msg = <span class="built_in">input</span>(<span class="string">&#x27;--------&gt;&#x27;</span>).strip()</span><br><span class="line">    phone.send(msg.encode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">    data = phone.recv(<span class="number">1024</span>)</span><br><span class="line">    <span class="built_in">print</span>(data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 关闭连接(必须)</span></span><br><span class="line">    phone.close()</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="四、通信循环"><a href="#四、通信循环" class="headerlink" title="四、通信循环"></a>四、通信循环</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	看上述的客户端服务端的代码，你会发现一个极其尴尬的事情，当两个互相打电话的时候，客户端说了一句你好，服务端也说了一句你好。然后就挂掉了电话，这样不是两个傻子么，所以我们要改进</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">	<span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    iphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  <span class="comment"># 流式协议</span></span><br><span class="line">    <span class="comment"># 装手机卡</span></span><br><span class="line">    iphone.bind((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line">    <span class="comment"># 开机</span></span><br><span class="line">    iphone.listen(<span class="number">5</span>)  <span class="comment"># 5指的是半连接池的大小</span></span><br><span class="line">    <span class="comment"># 等人打电话：拿到电话连接conn</span></span><br><span class="line">   </span><br><span class="line">    conn, client_addr = iphone.accept()</span><br><span class="line">    <span class="built_in">print</span>(conn)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;客户端的IP和端口&#x27;</span>, client_addr)</span><br><span class="line">    <span class="comment"># 通信中 </span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data = conn.recv(<span class="number">1024</span>)  <span class="comment"># 最大接受量为1024个字节</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;客户端收来的消息数据&#x27;</span>, data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">        conn.send(data.upper())</span><br><span class="line">    <span class="comment"># 关闭通信</span></span><br><span class="line">    conn.close()</span><br><span class="line">    <span class="comment"># 关闭手机（可选操作）</span></span><br><span class="line">    iphone.close()</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">	<span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 直接拨打电话</span></span><br><span class="line">    phone.connect((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 通信</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        msg = <span class="built_in">input</span>(<span class="string">&#x27;--------&gt;&#x27;</span>).strip()</span><br><span class="line">        phone.send(msg.encode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">        data = phone.recv(<span class="number">1024</span>)</span><br><span class="line">        <span class="built_in">print</span>(data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 关闭连接(必须)</span></span><br><span class="line">    phone.close()</span><br><span class="line">    </span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;加两个while循环其实就好了&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure>

<h2 id="五、bug1"><a href="#五、bug1" class="headerlink" title="五、bug1"></a>五、bug1</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	我们加了连接循环是不是就以为这两段代码完美了呢，其实不是，这两段代码还是有两个重要bug的，所以我们既然知道就得想办法去解决这两个bug，第一个BUG就是我们直接客户端去发送空数据，也就是直接按回车，这时候会发生客户端停滞了，所以这个bug很致命</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">	<span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    iphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  <span class="comment"># 流式协议</span></span><br><span class="line">    <span class="comment"># 装手机卡</span></span><br><span class="line">    iphone.bind((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line">    <span class="comment"># 开机</span></span><br><span class="line">    iphone.listen(<span class="number">5</span>)  <span class="comment"># 5指的是半连接池的大小</span></span><br><span class="line">    <span class="comment"># 等人打电话：拿到电话连接conn</span></span><br><span class="line">   </span><br><span class="line">    conn, client_addr = iphone.accept()</span><br><span class="line">    <span class="built_in">print</span>(conn)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;客户端的IP和端口&#x27;</span>, client_addr)</span><br><span class="line">    <span class="comment"># 通信中 </span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data = conn.recv(<span class="number">1024</span>)  <span class="comment"># 最大接受量为1024个字节</span></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;客户端收来的消息数据&#x27;</span>, data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">        conn.send(data.upper())</span><br><span class="line">    <span class="comment"># 关闭通信</span></span><br><span class="line">    conn.close()</span><br><span class="line">    <span class="comment"># 关闭手机（可选操作）</span></span><br><span class="line">    iphone.close()</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 直接拨打电话</span></span><br><span class="line">    phone.connect((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 通信</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        msg = <span class="built_in">input</span>(<span class="string">&#x27;--------&gt;&#x27;</span>).strip()</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">len</span>(msg) == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">            phone.send(msg.encode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">            data = phone.recv(<span class="number">1024</span>)</span><br><span class="line">            <span class="built_in">print</span>(data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            <span class="comment"># 关闭连接(必须)</span></span><br><span class="line">            phone.close()</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	我们可以加入一个if判断来判断用户输入是不是空的，如果是空的直接跳过这一次循环就好了，接下来说明一下为什么这个会BUG还有send， recv的原理</span></span><br><span class="line"><span class="string">	首先来讲BUG，为什么发送空数据会出现BUG，我们先来分析客户端，msg用户输入东西后，会是在send这里发生了bug吗，我们可以做一个测试，在send下面加一个print，看看这个会不会输出，如果输出了就不会是send的问题，我们加入了后，发现确实不是send问题，那么问题肯定就在recv呀，接受这方面出了问题，那我们去看服务端，服务端一开始就是recv，接受，那8说了，肯定是接收的问题，我们这边客户端发出了空数据，服务端那边接受不到，所以就一直等一直等，所以就会发生停滞，是这样的</span></span><br><span class="line"><span class="string">	然后我们来讲讲send 与 recv的区别，大家是不是以为send 与 recv是对应的关系，其实不是的，我们用socket模块把数据都封装打包后，传到网卡，但是我们是通过什么传到网卡呢，当然是操作系统了，我们把客户端的send重复写很多遍加入，但是服务端依然只有一次recv，这样行吗，当然可以，他们之间的流程是这样的，客户端一直send输入到数据里，然后通过操作系统调用网卡，在到服务端的网卡，在通过操作系统，来传到服务端，所以服务端还是只用接收一次就好了，所以流程是这样的</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">     </span><br></pre></td></tr></table></figure>

<h2 id="六、Bug2"><a href="#六、Bug2" class="headerlink" title="六、Bug2"></a>六、Bug2</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	别激动，还有一个大BUG呢，我们在运行服务端 客户端的时候，假如客户端突然停电了，中止了，这时候服务端就会出现分情况BUG，假如你是windows系统，你的服务端会直接报错 出现一个被迫中止了连接，如果你是linux或者Mac本，就会出现巨烧CPU的死循环BUG，所以我们要想办法去解决她</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 直接拨打电话</span></span><br><span class="line">    phone.connect((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 通信</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">            msg = <span class="built_in">input</span>(<span class="string">&#x27;--------&gt;&#x27;</span>).strip()</span><br><span class="line">            <span class="keyword">if</span> <span class="built_in">len</span>(msg) == <span class="number">0</span>:</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">                phone.send(msg.encode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">                data = phone.recv(<span class="number">1024</span>)</span><br><span class="line">                <span class="built_in">print</span>(data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 关闭连接(必须)</span></span><br><span class="line">    phone.close()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 买手机</span></span><br><span class="line">    iphone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  <span class="comment"># 流式协议</span></span><br><span class="line">    <span class="comment"># 装手机卡</span></span><br><span class="line">    iphone.bind((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line">    <span class="comment"># 开机</span></span><br><span class="line">    iphone.listen(<span class="number">5</span>)  <span class="comment"># 5指的是半连接池的大小</span></span><br><span class="line">    <span class="comment"># 等人打电话：拿到电话连接conn</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn, client_addr = iphone.accept()</span><br><span class="line">        <span class="built_in">print</span>(conn)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&#x27;客户端的IP和端口&#x27;</span>, client_addr)</span><br><span class="line">        <span class="comment"># 通信中</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">                data = conn.recv(<span class="number">1024</span>)  <span class="comment"># 最大接受量为1024个字节</span></span><br><span class="line">                <span class="built_in">print</span>(<span class="string">&#x27;客户端收来的消息数据&#x27;</span>, data.decode(<span class="string">&#x27;utf-8&#x27;</span>))</span><br><span class="line">                conn.send(data.upper())</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">    <span class="comment"># 关闭通信</span></span><br><span class="line">    conn.close()</span><br><span class="line">    <span class="comment"># 关闭手机（可选操作）</span></span><br><span class="line">    iphone.close()</span><br><span class="line"></span><br><span class="line">    </span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	我们就运用异常处理，来解决这个bug，我们假如只用了异常处理，就会发现客户端假如突然终止，服务器就直接关闭了，我们可不要这样，因为服务器关闭的场合真的太少太少，基本服务器不可能关闭的，所以我们又加了一个循环来保证服务器不是关闭状态</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure>

<h2 id="七、链接循环"><a href="#七、链接循环" class="headerlink" title="七、链接循环"></a>七、链接循环</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">```</span><br><span class="line"></span><br><span class="line"><span class="comment">## 八、半链接池</span></span><br><span class="line"></span><br><span class="line">```python</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	上面的代码可以看出半连接池只有5个程序的容量，我们怎么去仔细研究这个半连接池呢，我们可以多建立几个客户端，建立6个，然后我们启动5个客户端，你便发现，只有第一个在成功运行，后面4个都是停滞等待状态，如果这时候我们运行第6个，便发现客户端一点反应都没有，等过一段时间就会报错，然后我们停止客户端1，我们就发现客户端2就可以正常与服务端进行数据传输，然后这时候半连接池只有4个客户端在排队了，我们在运行客户端6，这个时候客户端6就会进去排队</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure>

<h2 id="九、基于UDP协议的简单网络通信"><a href="#九、基于UDP协议的简单网络通信" class="headerlink" title="九、基于UDP协议的简单网络通信"></a>九、基于UDP协议的简单网络通信</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">UDP的协议就比较简单了，因为他是不可靠协议，不需要建立连接双向通道</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    phone = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  <span class="comment"># 数据报协议-----&gt;UDP协议</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        msg = <span class="built_in">input</span>(<span class="string">&#x27;--------&gt;&#x27;</span>).strip()</span><br><span class="line">        phone.sendto(msg.encode(<span class="string">&#x27;utf-8&#x27;</span>), (<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line">        data, server_addr = phone.recvfrom(<span class="number">1024</span>)</span><br><span class="line">        <span class="built_in">print</span>(data.decode(<span class="string">&#x27;UTF_8&#x27;</span>), server_addr)</span><br><span class="line">    phone.close()</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  </span><br><span class="line">    server.bind((<span class="string">&#x27;192.168.11.197&#x27;</span>, <span class="number">8080</span>))</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        data, client_addr = server.recvfrom(<span class="number">1024</span>)  <span class="comment"># 最大接受量为1024个字节</span></span><br><span class="line">        <span class="built_in">print</span>(data.decode(<span class="string">&#x27;utf-8&#x27;</span>), client_addr)</span><br><span class="line">        server.sendto(data.upper(), client_addr)</span><br><span class="line"></span><br><span class="line">    iphone.close()</span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    	判断是不是会有TCP一样的bug：其实一个都不会有，因为他们并没有建立双向连接通道，客户端发出数据请求，服务端也不会回应，相反也是如此，所以TCP的BUG，UDP都不会出现，但也正因如此TCP的数据可靠性很强，而UDP数据可靠性就不强了</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h2 id="十、远程执行命令程序引出TCP协议的粘包问题"><a href="#十、远程执行命令程序引出TCP协议的粘包问题" class="headerlink" title="十、远程执行命令程序引出TCP协议的粘包问题"></a>十、远程执行命令程序引出TCP协议的粘包问题</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 粘包就是上一次传入的数据没有一次收干净，跟下一次的数据混合在了一起</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line">    <span class="keyword">import</span> subprocess</span><br><span class="line"></span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    服务端的两个要求</span></span><br><span class="line"><span class="string">        1.要一直运行，对外提供服务</span></span><br><span class="line"><span class="string">        2.要并发服务多个客户端</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line">    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">    server.bind((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">6668</span>))</span><br><span class="line">    server.listen(<span class="number">5</span>)  <span class="comment"># 设置半连接池的大小</span></span><br><span class="line">    <span class="comment"># 服务端应该做的两件事 1.服务端应该循环从半连接池拿出连接请求与其建立连接关系，拿到连接对象</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn, client_addr = server.accept()</span><br><span class="line">        <span class="comment"># 2.服务端拿到连接对象应该对其接受数据还有发出数据，进通信循环</span></span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                cmd = conn.recv(<span class="number">1024</span>)</span><br><span class="line">                <span class="keyword">if</span> <span class="built_in">len</span>(cmd) == <span class="number">0</span>:</span><br><span class="line">                    <span class="keyword">break</span></span><br><span class="line">                obj = subprocess.Popen(cmd.decode(<span class="string">&#x27;utf8&#x27;</span>),</span><br><span class="line">                                       shell=<span class="literal">True</span>,</span><br><span class="line">                                       stdout=subprocess.PIPE,</span><br><span class="line">                                       stderr=subprocess.PIPE)</span><br><span class="line">                stdout_res = obj.stdout.read()</span><br><span class="line">                stderr_res = obj.stderr.read()</span><br><span class="line">                conn.send(stdout_res)</span><br><span class="line">                conn.send(stderr_res)</span><br><span class="line">            <span class="keyword">except</span> Exception:</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">        conn.close()</span><br><span class="line">    </span><br><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line">    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  <span class="comment"># 流式协议</span></span><br><span class="line">    client.connect((<span class="string">&quot;127.0.0.1&quot;</span>, <span class="number">6668</span>))</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        msg = <span class="built_in">input</span>(<span class="string">&#x27;--------------&gt;&#x27;</span>).strip()</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">len</span>(msg) == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        client.send(msg.encode(<span class="string">&#x27;utf8&#x27;</span>))</span><br><span class="line">        <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">        解决粘包的具体思路</span></span><br><span class="line"><span class="string">            1.拿到数据的总大小 data_size</span></span><br><span class="line"><span class="string">            2.建立一个变量 recv_size 初始值为0，然后循环每收一次数据就 += 接受的长度</span></span><br><span class="line"><span class="string">            3.直到变量recv_size跟数据总大小 data_size 是一样的</span></span><br><span class="line"><span class="string">        &#x27;&#x27;&#x27;</span></span><br><span class="line">        cmd_res = client.recv(<span class="number">1024</span>)  <span class="comment"># 最大接受值 1024</span></span><br><span class="line">        <span class="built_in">print</span>(cmd_res.decode(<span class="string">&#x27;gbk&#x27;</span>))</span><br><span class="line"></span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    粘包问题出现的原因</span></span><br><span class="line"><span class="string">        1.tcp协议是流式协议，数据像流水一样，没有边界</span></span><br><span class="line"><span class="string">        2.一次没有收干净，然后剩下的数据也没有消失，然后下一次就会粘到一起</span></span><br><span class="line"><span class="string">    解决的核心办法就是</span></span><br><span class="line"><span class="string">        直接收干净，不留任何残留</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure>

<h2 id="十一、TCP协议的Nagle算法介绍与UDP介绍"><a href="#十一、TCP协议的Nagle算法介绍与UDP介绍" class="headerlink" title="十一、TCP协议的Nagle算法介绍与UDP介绍"></a>十一、TCP协议的Nagle算法介绍与UDP介绍</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">TCP协议采用了nagle算法，这个算法是将发送间隔短的量也小的数据都合在一起发送</span></span><br><span class="line"><span class="string">TCP（transport control protocol，传输控制协议）是面向连接的，面向流的，提供高可靠性服务。收发两端（客户端和服务器端）都要有一一成对的socket，因此，发送端为了将多个发往接收端的包，更有效的发到对方，使用了优化方法（Nagle算法），将多次间隔较小且数据量小的数据，合并成一个大的数据块，然后进行封包。这样，接收端，就难于分辨出来了，必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment"># UDP介绍</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">	UDP是没有粘包的，UDP也是没有nagle算法的，面对间隔短量小的数据分批发送，也得多次接收才可以，然后TCP数据量大，没有接收到的部分会一直放在缓存，而UDP会直接扔掉，所以这也是不可靠协议的一个特征</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure>

<h2 id="十二、自定义协议解决粘包问题"><a href="#十二、自定义协议解决粘包问题" class="headerlink" title="十二、自定义协议解决粘包问题"></a>十二、自定义协议解决粘包问题</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 自定义协议解决得用到新模块 struct</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 客户端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line">    <span class="keyword">import</span> struct</span><br><span class="line"></span><br><span class="line">    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  <span class="comment"># 流式协议</span></span><br><span class="line">    client.connect((<span class="string">&quot;127.0.0.1&quot;</span>, <span class="number">6668</span>))</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        msg = <span class="built_in">input</span>(<span class="string">&#x27;--------------&gt;&#x27;</span>).strip()</span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">len</span>(msg) == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        client.send(msg.encode(<span class="string">&#x27;utf8&#x27;</span>))</span><br><span class="line">        <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">        解决粘包的具体思路</span></span><br><span class="line"><span class="string">            1.拿到数据的总大小 data_size</span></span><br><span class="line"><span class="string">            2.建立一个变量 recv_size 初始值为0，然后循环每收一次数据就 += 1024</span></span><br><span class="line"><span class="string">            3.直到变量recv_size跟数据总大小 data_size 是一样的</span></span><br><span class="line"><span class="string">        &#x27;&#x27;&#x27;</span></span><br><span class="line">        <span class="comment"># 先收固定的头信息</span></span><br><span class="line">        header = client.recv(<span class="number">4</span>)</span><br><span class="line">        data_size = struct.unpack(<span class="string">&#x27;i&#x27;</span>, header)[<span class="number">0</span>]</span><br><span class="line">        <span class="comment"># 再收真实数据</span></span><br><span class="line">        recv_size = <span class="number">0</span></span><br><span class="line">        <span class="keyword">while</span> recv_size &lt; data_size:</span><br><span class="line">            cmd_res = client.recv(<span class="number">1024</span>)  <span class="comment"># 最大接受值 1024</span></span><br><span class="line">            recv_size += <span class="built_in">len</span>(cmd_res)</span><br><span class="line">            <span class="built_in">print</span>(cmd_res.decode(<span class="string">&#x27;gbk&#x27;</span>))</span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    粘包问题出现的原因</span></span><br><span class="line"><span class="string">        1.tcp协议是流式协议，数据像流水一样，没有边界</span></span><br><span class="line"><span class="string">        2.一次没有收干净，然后剩下的数据也没有消失，然后下一次就会粘到一起</span></span><br><span class="line"><span class="string">    解决的核心办法就是</span></span><br><span class="line"><span class="string">        直接收干净，不留任何残留</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line">    </span><br><span class="line"><span class="comment"># 服务端</span></span><br><span class="line">    <span class="keyword">import</span> socket</span><br><span class="line">    <span class="keyword">import</span> struct</span><br><span class="line">    <span class="keyword">import</span> subprocess</span><br><span class="line"></span><br><span class="line">    <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    服务端的两个要求</span></span><br><span class="line"><span class="string">        1.要一直运行，对外提供服务</span></span><br><span class="line"><span class="string">        2.要并发服务多个客户端</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line">    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)</span><br><span class="line">    server.bind((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">6668</span>))</span><br><span class="line">    server.listen(<span class="number">5</span>)  <span class="comment"># 设置半连接池的大小</span></span><br><span class="line">    <span class="comment"># 服务端应该做的两件事 1.服务端应该循环从半连接池拿出连接请求与其建立连接关系，拿到连接对象</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        conn, client_addr = server.accept()</span><br><span class="line">        <span class="comment"># 2.服务端拿到连接对象应该对其接受数据还有发出数据，进通信循环</span></span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                cmd = conn.recv(<span class="number">1024</span>)</span><br><span class="line">                <span class="keyword">if</span> <span class="built_in">len</span>(cmd) == <span class="number">0</span>:</span><br><span class="line">                    <span class="keyword">break</span></span><br><span class="line">                obj = subprocess.Popen(cmd.decode(<span class="string">&#x27;utf8&#x27;</span>),</span><br><span class="line">                                       shell=<span class="literal">True</span>,</span><br><span class="line">                                       stdout=subprocess.PIPE,</span><br><span class="line">                                       stderr=subprocess.PIPE)</span><br><span class="line">                stdout_res = obj.stdout.read()</span><br><span class="line">                stderr_res = obj.stderr.read()</span><br><span class="line">                <span class="comment"># 数据的总大小</span></span><br><span class="line">                data_size = <span class="built_in">len</span>(stdout_res) + <span class="built_in">len</span>(stderr_res)</span><br><span class="line">                <span class="comment"># 面对这个总大小，假如我们直接send发送就会沾到一块，所以得想办法解决</span></span><br><span class="line">                <span class="comment"># 先包装成头(固定字节)：对数据描述信息  int---&gt;字节类型</span></span><br><span class="line">                header = struct.pack(<span class="string">&#x27;i&#x27;</span>, data_size)</span><br><span class="line">                conn.send(header)</span><br><span class="line">                <span class="comment"># 再发真实的数据</span></span><br><span class="line">                conn.send(stdout_res)</span><br><span class="line">                conn.send(stderr_res)</span><br><span class="line">            <span class="keyword">except</span> Exception:</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">        conn.close()	</span><br></pre></td></tr></table></figure>

<h2 id="十三、解决粘包问题终极大招"><a href="#十三、解决粘包问题终极大招" class="headerlink" title="十三、解决粘包问题终极大招"></a>十三、解决粘包问题终极大招</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&#x27;&#x27;&#x27;这是发数据字符串，万一我们要传输文件，视频，图片啊，怎么办&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure>


            </div>

            <!-- Post Comments -->
            
    <!-- 使用 DISQUS_CLICK -->
<div id="disqus-comment">
    <div id="disqus_thread"></div>

<!-- add animation -->
<style>
	.disqus_click_btn {
            line-height: 30px;
            margin: 0;
            min-width: 50px;
            padding: 0 14px;
            display: inline-block;
            font-family: "Roboto", "Helvetica", "Arial", sans-serif;
            font-size: 14px;
            font-weight: 400;
            text-transform: uppercase;
            letter-spacing: 0;
            overflow: hidden;
            will-change: box-shadow;
            transition: box-shadow .2s cubic-bezier(.4, 0, 1, 1), background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1);
            outline: 0;
            cursor: pointer;
            text-decoration: none;
            text-align: center;
            vertical-align: middle;
            border: 0;
            background: rgba(158, 158, 158, .2);
            box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
            color: #fff;
            background-color: #7EC0EE;
            text-shadow: 0
        }
</style>
	
<div class="btn_click_load" id="disqus_bt"> 
    <button class="disqus_click_btn">点击查看评论</button>
</div>

<!--
<script type="text/javascript">
$('.btn_click_load').click(function() {
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'http-miccall-tech'; // required: replace example with your forum shortname

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();

    document.getElementById('disqus_bt').style.display = "none";
});
</script>
-->
<script type="text/javascript">
    var disqus_config = function () {
        this.page.url = 'https://gitee.com/AmeX/amelin-ting.git/2017/04/01/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/';  // Replace PAGE_URL with your page's canonical URL variable
        this.page.identifier = 'https://gitee.com/AmeX/amelin-ting.git/2017/04/01/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
    };
</script>

<script type="text/javascript">
    $('.btn_click_load').click(function() {  //click to load comments
        (function() { // DON'T EDIT BELOW THIS LINE
            var d = document;
            var s = d.createElement('script');
            s.src = '//http-miccall-tech.disqus.com/embed.js';
            s.setAttribute('data-timestamp', + new Date());
            (d.head || d.body).appendChild(s);
        })();
        $('.btn_click_load').css('display','none');
    });
</script>
</div>
<style>
    #disqus-comment{
        background-color: #eee;
        padding: 2pc;
    }
</style>


        </div>
        <!-- Copyright 版权 start -->
                <div id="copyright">
            <ul>
                <li>&copy;Powered By <a target="_blank" rel="noopener" href="https://hexo.io/zh-cn/" style="border-bottom: none;">hexo</a></li>
                <li>Design: <a target="_blank" rel="noopener" href="http://miccall.tech " style="border-bottom: none;">miccall</a></li>
            </ul>
            
                <span id="busuanzi_container_site_pv">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
			
        </div>
    </div>
</body>



 	
</html>
